package cn.com.thinker.security.sdk.config;

import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.Filter;

import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import cn.com.thinker.security.sdk.shiro.cache.RedisCacheManager;
import cn.com.thinker.security.sdk.shiro.dto.FilterDTO;
import cn.com.thinker.security.sdk.shiro.propertise.ShiroProperties;
import cn.com.thinker.security.sdk.sso.filter.Thin4soClientFilter;
import cn.com.thinker.security.sdk.sso.filter.Thin4soClientLogoutFilter;
import cn.com.thinker.security.sdk.sso.filter.Thin4soLogoutJavascriptFilter;

/**
 * Created by crazyHC on 2017/6/27.
 */

@Configuration
@ConditionalOnMissingClass("cn.com.thinker.security.server.config.SecurityServerConfig")
public class ShiroConfig {
	
		
    @Resource
    private ShiroProperties shiroProperties;
    
    @Resource
    private Filter ssoLoginFilter;
    @Resource
    private AuthorizingRealm ssoRealm;
    
    @Resource
    private AuthorizingRealm systemAuthorizingRealm;
    
//    @Resource
    private UserFilter userFilter;
    
    
    @Bean
    public FilterRegistrationBean thinkerShiroFilter() {
        FilterRegistrationBean filter = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy("shiroFilter");
        proxy.setTargetFilterLifecycle(true);
        filter.setFilter(proxy);
        filter.setUrlPatterns(Lists.newArrayList("/*"));
        return filter;
    }



    /**
     * 分布式缓存管理
     *
     * @return
     */
    @Bean
    public RedisCacheManager redisCacheManager() {
        return new RedisCacheManager();
    }

    /**
     * 使用spring session处理
     *
     * @return
     */
    @Bean("servletContainerSessionManager")
    public ServletContainerSessionManager servletContainerSessionManager() {
        return new ServletContainerSessionManager();
    }

    /**
     * 用于web环境的安全管理器
     *
     * @return
     * @throws ClassNotFoundException 
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSessionManager(servletContainerSessionManager());
        	
       /* try {
        	
        	if(null != Class.forName("com.thinker.icare.modules.sys.security.SystemAuthorizingRealm")) {
        		securityManager.setRealm( (Realm) SpringContextUtils.getBean(Class.forName("com.thinker.icare.modules.sys.security.SystemAuthorizingRealm")));
        		System.out.println("进systemReaLm");
        	}
        	else {
        		System.out.println("进ssoEeaml");
        securityManager.setRealm(ssoRealm);
        	}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}*/
        if(null != systemAuthorizingRealm) {
        	System.out.println("进来systemAuthorizingRealm");
        	securityManager.setRealm(systemAuthorizingRealm);
        	
        } else {
        	securityManager.setRealm(ssoRealm);
        }
        
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager());
        return new AuthorizationAttributeSourceAdvisor();
    }

    /**
     * 通过spring来初始化shiro的工作环境
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        FilterDTO filter = shiroProperties.getFilter();
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        shiroFilterFactoryBean.setLoginUrl(filter.getLoginUrl());
        shiroFilterFactoryBean.setSuccessUrl(filter.getLoginSuccessUrl());
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filter.getChain());

        Map<String, Filter> filters = Maps.newHashMap();
        filters.put("authc", new FormAuthenticationFilter());
        if (null != userFilter) {
        	System.out.println("有userFilter");
        	filters.put("user",userFilter);
			
		}
       
        filters.put("ssoLogin",ssoLoginFilter);
        shiroFilterFactoryBean.setFilters(filters);
        return shiroFilterFactoryBean;
    }

    @Bean
    public MethodInvokingFactoryBean setSecurityManager() {
        MethodInvokingFactoryBean invoke = new MethodInvokingFactoryBean();
        invoke.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        invoke.setArguments(new Object[]{securityManager()});
        return invoke;
    }


    /**
     * sso client must set, and always on top
     * @return
     */
    @Bean
    @ConditionalOnProperty(prefix = "thinker.shiro.sso",value="enabled")
    public FilterRegistrationBean clientFilter(){
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new Thin4soClientFilter());
        Map<String,String> params = Maps.newHashMap();
        // sso服务器主机地址
        params.put("thin4soServerHost",shiroProperties.getSso().getSecurityServerUrl());
        // sso服务器登录地址
        params.put("thin4soServerLoginUrl",shiroProperties.getSso().getSecurityServerLoginUrl());
        // sso服务器获取应用秘钥信息的URL地址
        params.put("thin4soServerFetchKeyUrl",shiroProperties.getSso().getFetchKeyUrl());
        // sso本应用在服务器上的应用ID值
        params.put("thin4soClientAppId",shiroProperties.getSso().getClientAppId());
        params.put("appClientLoginHandlerClass",shiroProperties.getSso().getLoginHandler());
        filter.setInitParameters(params);
        filter.setUrlPatterns(Lists.newArrayList(shiroProperties.getFilter().getAdminPath()+"/*"));
        filter.setOrder(0);
        return filter;
    }

    /**
     * sso local logout
     * @return
     */
    @Bean
    @ConditionalOnProperty(prefix = "thinker.shiro.sso",value="enabled")
    public FilterRegistrationBean clientLogoutFilter(){
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new Thin4soClientLogoutFilter());
        Map<String,String> params = Maps.newHashMap();
        // sso服务器主机地址
        params.put("appClientLogoutHandlerClass",shiroProperties.getSso().getLogoutHandler());
        filter.setInitParameters(params);
        filter.setUrlPatterns(Lists.newArrayList(shiroProperties.getFilter().getLogoutUrl()));
        filter.setOrder(0);
        return filter;
    }


    /**
     * sso logout.js filter
     * @return
     */
    @Bean
    @ConditionalOnProperty(prefix = "thinker.shiro.sso",value="enabled")
    public FilterRegistrationBean logoutJavaScriptFilter(){
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new Thin4soLogoutJavascriptFilter());
        Map<String,String> params = Maps.newHashMap();
        // 当前应用的登出地址
        params.put("currentAppLogoutUrl",shiroProperties.getFilter().getLogoutUrl());
        // 登出后跳转地址
        params.put("logoutSuccessUrl",shiroProperties.getFilter().getLogoutSuccessUrl());
        // sso服务器主机地址
        params.put("thin4soServerHost",shiroProperties.getSso().getSecurityServerUrl());
        filter.setInitParameters(params);
        filter.setUrlPatterns(Lists.newArrayList("/logout.js"));
        return filter;
    }
}
